package com.baoteng.captcha.recognition.service.impl;

import java.awt.Color;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.stream.Collectors;

import javax.imageio.ImageIO;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.baoteng.captcha.recognition.vo.CaptchaVO;
import com.baoteng.captcha.recognition.vo.PAEigenvalue;
import com.baoteng.captcha.recognition.vo.RecognizeResultVO;
import com.baoteng.captcha.recognition.vo.SingleCharImageBuffer;
import com.google.common.collect.Maps;
import com.google.common.io.PatternFilenameFilter;

import net.sourceforge.tess4j.ITessAPI.TessPageSegMode;
import net.sourceforge.tess4j.ITesseract;
import net.sourceforge.tess4j.Tesseract1;

@Service("pinganCaptchaService")
public class PinganCaptchaService {

	@Value("${tess.data.path:D\\:/Tesseract-OCR/tessdata}")
	private String tessDataPath;

	@Value("${pa.test.data.path:}")
	private String testPath;
	
	public CaptchaVO test() throws Exception{
		if(!StringUtils.isNotBlank(testPath)){
			return null;
		}
		File dataPath = new File(testPath);
		if(!dataPath.exists()){
			throw new Exception("test data directory don`t exist.");
		}
		String[] fileList = dataPath.list(new PatternFilenameFilter("(.*\\.png$)"));
		if(fileList!=null && fileList.length>0){
			Random random = new Random();
			int index = random.nextInt(fileList.length);
			byte[] data = FileUtils.readFileToByteArray(new File(testPath+fileList[index]));
			String result= recognizeQueryCaptcha(data);
			if(StringUtils.isBlank(result)){
				 new RecognizeResultVO("404", "fail");
			}
			CaptchaVO vo = new CaptchaVO("0","succ");
			vo.setData(Base64.encodeBase64String(data));
			vo.setName(fileList[index].split("\\.")[0]);
			vo.setText(result);
			return vo;
		}else{
			throw new Exception("test data directory  is empty.");
		}
	}
	
	public String recognizeQueryCaptcha(byte[] imgData) {
		InputStream imgStream = new ByteArrayInputStream(imgData);
		int threshold = 100;
		try {
			BufferedImage bufferedImage = ImageIO.read(imgStream);
			int h = bufferedImage.getHeight();
			int w = bufferedImage.getWidth();
			Map<Integer, SingleCharImageBuffer> singleMap = Maps.newHashMap();
			for (int y = 0; y < h; y++) {
				for (int x = 0; x < w; x++) {
					int rgb = bufferedImage.getRGB(x, y);
					if (rgb != -1) {
						singleMap.merge(rgb, new SingleCharImageBuffer(rgb, x, x, y, y, 1), (befor, after) -> {
							after.setPixelTotal(befor.getPixelTotal() + 1);
							if(after.getDx1()>befor.getDx1())  after.setDx1(befor.getDx1());
							if(after.getDx2()<befor.getDx2())  after.setDx2(befor.getDx2());
							if(after.getDy1()>befor.getDy1())  after.setDy1(befor.getDy1());
							if(after.getDy2()<befor.getDy2())  after.setDy2(befor.getDy2());
							return after;
						});
					}
				}
			}
			singleMap = singleMap.entrySet().parallelStream()
					.filter((v) -> v.getValue().getPixelTotal() >= threshold ? true : false)
					.collect(Collectors.toMap(Entry::getKey, Entry::getValue));

			int currentColor = -1;
			int index = 0;
			for (int x = 0; x < w; x++) {
				for (int y = 0; y < h; y++) {
					int _rgb = bufferedImage.getRGB(x, y);
					if (_rgb != -1) {
						SingleCharImageBuffer currentChar = singleMap.get(_rgb);
						bufferedImage.setRGB(x, y, -1);
						if (currentChar != null) {
							bufferedImage.setRGB(x, y, Color.BLACK.getRGB());
//							if(currentChar.getBuffered()!=null) currentChar.getBuffered().setRGB(x - currentChar.getDx1() + 2, y - currentChar.getDy1() + 2,
//									Color.BLACK.getRGB());
							currentChar.setIndex(index);
							if (_rgb != currentColor) {
								currentColor = _rgb;
								index++;
							}
						}
					}
				}
			}
			StringBuilder sb = new StringBuilder();
			
			ITesseract singleTesseract = new Tesseract1();
			singleTesseract.setDatapath(tessDataPath);
			singleTesseract.setLanguage("prc");
			singleTesseract.setPageSegMode(TessPageSegMode.PSM_SINGLE_CHAR);
			
			singleMap.entrySet().stream().sorted((o1, o2) -> {
				return o1.getValue().getDx1()-o2.getValue().getDx1();
			}).forEach(entity -> {
				SingleCharImageBuffer _char = entity.getValue();
				int _weight = _char.getDx2() - _char.getDx1();
				int _height = _char.getDy2() - _char.getDy1();
				try {
//					String chartVC = singleTesseract.doOCR(_char.getBuffered());
					String chartVC = singleTesseract.doOCR(bufferedImage, new Rectangle(_char.getDx1()-1,_char.getDy1()-1,_char.getDx2() - _char.getDx1()+2,_char.getDy2()-_char.getDy1()+2));
					if (StringUtils.isNotBlank(chartVC)) {
						if (chartVC.length() >= 2) {
							chartVC = chartVC.substring(0, 1);
						}
						sb.append(chartVC);
					} else {
						chartVC = PAEigenvalue.newInstance().getCharOfPixels(_char.getPixelTotal(), _weight, _height);
						if (chartVC != null)
							sb.append(chartVC);
					}
				} catch (Exception ie) {

				}
			});
			return sb.toString();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

}
